package br.boicotando.client;

import java.util.ArrayList;
import java.util.List;

import br.boicotando.dominio.Categoria;
import br.boicotando.dominio.Produto;
import br.boicotando.dominio.Setor;
import br.boicotando.dominio.SubCategoria;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DecoratorPanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;


public class TelaSelecaoProduto extends Composite {

	// Outras classes
	public static class SelecaoProduto extends Composite {
    	
    	private VerticalPanel panel = new VerticalPanel();
    	private Produto produto;
    	private final HTML produtoHTML = new HTML();
    	private final Button comprarButton = new Button("COMPRAR");
    	
    	public SelecaoProduto(Produto p) {
	    	String html = "<img src=\"/boicotando" + p.getEnderecoImagem() + "\" /><br>" +
	    	              p.getDescricao() + "<br><b>R$" +
	    	              NumberFormat.getDecimalFormat().format(p.getValorUnitario().doubleValue()) +
	    	              "</b>";
    		produto = p;
    		
    		produtoHTML.setHTML(html);
    		
    		comprarButton.setStyleName("titulo");
    		comprarButton.addClickHandler(new ClickHandler() {
				@Override
				public void onClick(ClickEvent event) {
					Window.alert("Adicionado produto no carrinho: " + produto.getId());
				}
			});
    		
    		panel.add(produtoHTML);
    		panel.add(comprarButton);
    		
    		initWidget(panel);
    	}
    	
    }

	// Objetos de interface
	private final HorizontalPanel panel = new HorizontalPanel();
	private final DecoratorPanel bordaSetoresPanel = new DecoratorPanel();
	private final VerticalPanel setoresPanel = new VerticalPanel();
	private final TextBox buscaText = new TextBox();
    private final FlexTable produtosTable = new FlexTable();
    private final ListBox setoresList = new ListBox();
    private final VerticalPanel categoriasPanel = new VerticalPanel();
    private final VerticalPanel subCategoriasPanel = new VerticalPanel();
    private final List<CheckBox> categoriasChekBox = new ArrayList<CheckBox>();
    private final List<CheckBox> subCategoriasChekBox = new ArrayList<CheckBox>();
    
    // Handlers
    private ClickHandler categoriasClickHandler;
    private ClickHandler subCategoriasClickHandler;
    
    // Serviços WEB
    private static final GerenciadorLojaAsync gerenciadorLoja = GWT.create(GerenciadorLoja.class);
    
    // Objetos do modelo de dados
	private final List<Setor> setores;
    private int categoriasSelecionadas;
    private int subCategoriasSelecionadas;


	public TelaSelecaoProduto(List<Setor> setores) {
		this.setores = setores;
		bordaSetoresPanel.setStyleName("formulario", true);
		produtosTable.setStyleName("tabela", true);
		panel.add(bordaSetoresPanel);
		panel.add(produtosTable);
		bordaSetoresPanel.add(setoresPanel);
		setoresPanel.add(new HTML("<h2>Setores</h2>"));
		setoresPanel.add(setoresList);
		setoresPanel.add(new HTML("<h2>Busca</h2>"));
		setoresPanel.add(buscaText);
		setoresPanel.add(categoriasPanel);
		setoresPanel.add(subCategoriasPanel);

		setoresList.addItem("Produtos em destaque");
		if (setores != null) {
			for (Setor setor : setores) {
				setoresList.addItem(setor.getNome());
			}
		}
		setoresList.setSelectedIndex(0);
		setoresList.addChangeHandler(new ChangeHandler() {

			@Override
			public void onChange(ChangeEvent event) {
				listaCategorias();
			}
			
		});
		
		buscaText.addKeyUpHandler(new KeyUpHandler() {

			@Override
			public void onKeyUp(KeyUpEvent event) {
				if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
					listaProdutos();
				}
			}
			
		});
		
		listaProdutos();
	    initWidget(panel);
	}

	public Setor getSetorSelecionado() {
		Setor setor = null;
		int index = setoresList.getSelectedIndex() - 1;
		if (index >= 0) {
			setor = setores.get(index);
		}
		return setor;
	}
	
	private ClickHandler getCategoriasClickHandler() {
		if (categoriasClickHandler == null) {
			categoriasClickHandler = new ClickHandler() {

				@Override
				public void onClick(ClickEvent event) {
					if (((CheckBox) event.getSource()).getValue()) {
						++categoriasSelecionadas;
					} else {
						--categoriasSelecionadas;
					}
					listaSubCategorias();
				}
				
			};
		}
		return categoriasClickHandler;
	}
	
	private ClickHandler getSubCategoriasClickHandler() {
		if (subCategoriasClickHandler == null) {
			subCategoriasClickHandler = new ClickHandler() {

				@Override
				public void onClick(ClickEvent event) {
					if (((CheckBox) event.getSource()).getValue()) {
						++subCategoriasSelecionadas;
					} else {
						--subCategoriasSelecionadas;
					}
					listaProdutos();
				}
				
			};
		}
		return subCategoriasClickHandler;
	}

	private void listaCategorias() {
		Setor setor = getSetorSelecionado();
		categoriasChekBox.clear();
		categoriasPanel.clear();
		categoriasSelecionadas = 0;
		if (setor != null) {
			boolean primeiraCategoria = true;
			Categoria categorias[] = new Categoria[0];
			CheckBox check;
			categorias = setor.getCategorias(categorias);
			for (int i = 0; i < categorias.length; ++i) {
				check = new CheckBox(categorias[i].getNome());
				check.setFormValue(categorias[i].getId());
				check.addClickHandler(getCategoriasClickHandler());
				if (primeiraCategoria) {
					categoriasPanel.add(new HTML("<h2>Categorias</h2>"));
					primeiraCategoria = false;
				}
				categoriasPanel.add(check);
				categoriasChekBox.add(check);
			}
		}
		listaSubCategorias();
	}
	
	private void listaSubCategorias() {
		Setor setor = getSetorSelecionado();
		subCategoriasChekBox.clear();
		subCategoriasPanel.clear();
		subCategoriasSelecionadas = 0;
		if (setor != null) {
			boolean primeiraSubCategoria = true;
			Categoria categorias[] = new Categoria[0];
			SubCategoria subCategorias[] = new SubCategoria[0];
			CheckBox check;
			categorias = setor.getCategorias(categorias);
			for (int i = 0; i < categorias.length; ++i) {
				if (categoriaFoiSelecionada(categorias[i])) {
					subCategorias = categorias[i].getSubCategorias(subCategorias);
					for (int j = 0; j < subCategorias.length; ++j) {
						check = new CheckBox(subCategorias[j].getNome());
						check.setFormValue(subCategorias[j].getId());
						check.addClickHandler(getSubCategoriasClickHandler());
						if (primeiraSubCategoria) {
							subCategoriasPanel.add(new HTML("<h2>Subcategorias</h2>"));
							primeiraSubCategoria = false;
						}
						subCategoriasPanel.add(check);
						subCategoriasChekBox.add(check);
					}
				}
			}				
		}
		listaProdutos();
	}
	
	private void listaProdutos() {
		Setor setor = getSetorSelecionado();
		if (setor == null) {
			gerenciadorLoja.consultarProdutoDestaque(new AsyncCallback<List<Produto>>(){
				@Override
				public void onSuccess(List<Produto> produtos) {
					exibeProdutos(produtos);
				}
				
				@Override
				public void onFailure(Throwable caught) {
					Window.alert("Não foi possível recuperar os produtos em destaque: " + caught.getMessage());
				}
			});
		} else {
			List<Setor> setores = new ArrayList<Setor>();
			if (categoriasSelecionadas <= 0)  {
				setores.add(setor);
			}
			for (Categoria categoria : setor.getCategorias(new Categoria[0])) {
				if (categoriasSelecionadas <= 0 || categoriaFoiSelecionada(categoria)) {
					setores.add(categoria);
					for (SubCategoria subCategoria : categoria.getSubCategorias(new SubCategoria[0])) {
						if (subCategoriasSelecionadas <= 0 || subCategoriaFoiSelecionada(subCategoria)) {
							setores.add(subCategoria);
						}
					}
				}
			}
			exibeProdutosSetores(setores);
		}
	}
	
	private boolean subCategoriaFoiSelecionada(SubCategoria subCategoria) {
		for (CheckBox check : subCategoriasChekBox) {
			if (check.getFormValue().equals(subCategoria.getId())) {
				return check.getValue();
			}
		}
		return false;
	}

	private boolean categoriaFoiSelecionada(Categoria categoria) {
		for (CheckBox check : categoriasChekBox) {
			if (check.getFormValue().equals(categoria.getId())) {
				return check.getValue();
			}
		}
		return false;
	}
	
	private void exibeProdutosSetores(List<Setor> setores) {
		if (buscaText.getValue() == null || buscaText.getValue().isEmpty()) {
			gerenciadorLoja.consultarProdutos(setores, new AsyncCallback<List<Produto>>() {
				@Override
				public void onSuccess(List<Produto> produtos) {
					exibeProdutos(produtos);
				}
				
				@Override
				public void onFailure(Throwable caught) {
					Window.alert("Não foi possível recuperar os produtos: " + caught.getMessage());
				}
			});
		} else {
			gerenciadorLoja.consultarProdutos(setores, buscaText.getValue(), new AsyncCallback<List<Produto>>() {
				@Override
				public void onSuccess(List<Produto> produtos) {
					exibeProdutos(produtos);
				}
				
				@Override
				public void onFailure(Throwable caught) {
					Window.alert("Não foi possível recuperar os produtos: " + caught.getMessage());
				}
			});			
		}
	}

	private void exibeProdutos(List<Produto> produtos) {
		produtosTable.removeAllRows();
		for (Produto produto : produtos) {
			exibeProduto(produto);
		}
	}

    private void exibeProduto(Produto produto) {
    	if (produto != null) {
	    	int lin;
	    	int col;
	    	
	    	if (produtosTable.getRowCount() == 0) {
	    		lin = 0;
	    		col = 0;
	    	} else {
	    		lin = produtosTable.getRowCount() - 1;
	    		col = produtosTable.getCellCount(lin);
	    		if (col == 4) {
	    			++lin;
	    			col = 0;
	    		}
	    	}
	    		    	
	    	produtosTable.setWidget(lin, col, new SelecaoProduto(produto));
    	}
    }

}
